package com.tich.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tich.api.client.ProgramClient;
import com.tich.api.domain.dto.ProgramTicketAddDTO;
import com.tich.api.domain.dto.ProgramTicketDeductDTO;
import com.tich.api.domain.vo.ProgramClientSelectVO;
import com.tich.constant.ExceptionConstant;
import com.tich.constant.RabbitMqConstant;
import com.tich.context.UserContext;
import com.tich.enumration.IsStatus;
import com.tich.enumration.OrderStatus;
import com.tich.exception.*;
import com.tich.order.domain.dto.OrderInsertDTO;
import com.tich.order.domain.dto.OrderSimpleSelectDTO;
import com.tich.order.domain.dto.ViewerInfoInsertDTO;
import com.tich.order.domain.entity.Orders;
import com.tich.order.domain.entity.ViewerInfo;
import com.tich.order.domain.vo.OrderSelectVO;
import com.tich.order.domain.vo.OrderSimpleSelectVO;
import com.tich.order.domain.vo.OrderSimpleVO;
import com.tich.order.domain.vo.ViewerInfoSelectVO;
import com.tich.order.mapper.OrderMapper;
import com.tich.order.mapper.ViewerInfoMapper;
import com.tich.order.service.IOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tich.utils.IdGeneratorUtil;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements IOrderService {

    @Autowired
    private ProgramClient programClient;
    @Autowired
    private ViewerInfoMapper viewerInfoMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private OrderMapper orderMapper;

    /**
     * 生成订单
     * @param orderInsertDTO
     * */
    @GlobalTransactional
    public Long insertOrder(OrderInsertDTO orderInsertDTO) {
        //1.查询节目信息以及门票信息
        ProgramClientSelectVO programClientSelectVO = programClient.programClientSelect(orderInsertDTO.getProgramId(), orderInsertDTO.getTicketId()).getData();
        if(Objects.equals(programClientSelectVO.getStatus(), IsStatus.NO.getCode())){
            //如果节目下架则抛出异常
            throw new ProgramTakeOffException(ExceptionConstant.PROGRAM_TAKE_OFF);
        }
        //2.如果门票有剩余则扣减门票数量
        //TODO 实现一个账户只能买固定的单数
        if(programClientSelectVO.getRemainingCount() < orderInsertDTO.getCount()){
            //如果库存小于购买数则抛出异常
            throw new TicketLackException(ExceptionConstant.TICKET_LACK);
        }
        //3.发送扣减库存请求
        if(!programClient.programTicketDeduct(ProgramTicketDeductDTO.builder()
                   .ticketId(orderInsertDTO.getTicketId())
                   .count(orderInsertDTO.getCount())
                   .build())
                .getData()){
            //如果扣减库存失败则抛出异常
            throw new TicketPurchaseFailException(ExceptionConstant.TICKET_PURCHASE_FAIL);
        }
        //4.生成订单,并插入数据库
        Long id = IdGeneratorUtil.getInstance().nextId();
        Orders orders = Orders.builder()
                .id(id)
                .orderNumber(String.valueOf(System.currentTimeMillis()))
                .userId(UserContext.getCurrentId())
                .programId(orderInsertDTO.getProgramId())
                .ticketId(orderInsertDTO.getTicketId())
                .programPoster(programClientSelectVO.getPoster())
                .programTitle(programClientSelectVO.getTitle())
                .programPlace(programClientSelectVO.getPlace())
                .programShowTime(programClientSelectVO.getShowDayTime())
                .count(orderInsertDTO.getCount())
                .money(orderInsertDTO.getCount() * programClientSelectVO.getPrice())
                .build();
        save(orders);
        //5.生成观演人信息，并插入数据库
        List<ViewerInfo> viewerInfos = new ArrayList<>();
        List<ViewerInfoInsertDTO> viewerInfoInsertDTOList = orderInsertDTO.getViewerInfoInsertDTOList();
        for (ViewerInfoInsertDTO viewerInfoInsertDTO : viewerInfoInsertDTOList) {
            ViewerInfo viewerInfo = new ViewerInfo();
            viewerInfo.setOrderId(id);
            viewerInfo.setViewerName(viewerInfoInsertDTO.getViewerName());
            viewerInfo.setViewerPhone(viewerInfoInsertDTO.getViewerPhone());
            viewerInfo.setViewerId(viewerInfoInsertDTO.getViewerId());
            viewerInfos.add(viewerInfo);
        }
        viewerInfoMapper.insert(viewerInfos);
        //6.投递限时支付到MQ
        rabbitTemplate.convertAndSend(RabbitMqConstant.ORDER_DELAY_DIRECT,
                RabbitMqConstant.ORDER_PAY_DELAY_KEY,
                id,
                message -> {
                    message.getMessageProperties().setDelayLong(15L * 60 * 1000);
                    return message;
                });
        return id;
    }

    /**
     * 取消订单
     * @param id
     * */
    @GlobalTransactional
    public void cancelOrder(Long id) {
        //1.查询订单
        Orders orders = orderMapper.selectById(id);
        if(orders.getOrderStatus() != OrderStatus.UNPAID.getCode()){
            //如果订单不是未支付状态则不允许取消
            throw new OrderStatusException(ExceptionConstant.ORDER_CANCEL_OR_PAID);
        }
        //2.将订单状态改为已取消
        LambdaUpdateWrapper<Orders> orderLambdaUpdateWrapper = Wrappers.lambdaUpdate(Orders.class)
                .set(Orders::getOrderStatus, OrderStatus.CANCELLED.getCode())
                .set(Orders::getCancelOrderTime, LocalDateTime.now())
                .eq(Orders::getId, orders.getId());
        orderMapper.update(orderLambdaUpdateWrapper);
        //3.恢复库存
        ProgramTicketAddDTO programTicketAddDTO = ProgramTicketAddDTO.builder()
                .ticketId(orders.getTicketId())
                .count(orders.getCount())
                .build();
        programClient.programTicketAdd(programTicketAddDTO);
    }

    /**
     * 删除订单
     * @param id
     * @return
     * */
    public void deleteOrder(Long id) {
        //1.查询订单
        Orders orders = orderMapper.selectById(id);
        if(orders.getOrderStatus() == OrderStatus.UNPAID.getCode()){
            //如果订单未支付则不允许删除
            throw new OrderUnpaidException(ExceptionConstant.ORDER_UNPAID);
        }
        //2.删除订单
        orderMapper.deleteById(id);
        //3.将订单存入一个数据库
        rabbitTemplate.convertAndSend(RabbitMqConstant.ORDER_DIRECT,
                RabbitMqConstant.ORDER_DELETE_KEY,
                orders);
    }

    /**
     * 查询用户的所有订单简略信息
     * @param orderSimpleSelectDTO
     * @return
     * */
    public OrderSimpleSelectVO simpleSelectOrders(OrderSimpleSelectDTO orderSimpleSelectDTO) {
        //1.查询该用户的所有订单
        LambdaQueryWrapper<Orders> orderLambdaQueryWrapper = Wrappers.lambdaQuery(Orders.class)
                .eq(Orders::getUserId, UserContext.getCurrentId())
                .lt(Orders::getCreateTime, orderSimpleSelectDTO.getCursor())
                .orderByDesc(Orders::getCreateTime)
                .last("limit " + orderSimpleSelectDTO.getCount());
        List<Orders> orders = orderMapper.selectList(orderLambdaQueryWrapper);
        //2.获取cursor
        LocalDateTime cursor = null;
        if(!CollectionUtil.isEmpty(orders)){
            cursor = orders.get(orders.size() - 1).getCreateTime();
        }
        //3.封装返回体
        List<OrderSimpleVO> orderSimpleVOS = orders.stream()
                .map(order -> new OrderSimpleVO()
                        .setId(order.getId())
                        .setOrderNumber(order.getOrderNumber())
                        .setTicketCategory(programClient.ticketCategorySelect(order.getTicketId()).getData())
                        .setProgramTitle(order.getProgramTitle())
                        .setProgramPoster(order.getProgramPoster())
                        .setCount(order.getCount())
                        .setMoney(order.getMoney()))
                .toList();
        OrderSimpleSelectVO orderSimpleSelectVO = new OrderSimpleSelectVO();
        orderSimpleSelectVO.setOrderSelectVOS(orderSimpleVOS);
        orderSimpleSelectVO.setCursor(cursor);
        return orderSimpleSelectVO;
    }

    /**
     * 查询单个订单的详细信息
     * @param id
     * @return
     * */
    public OrderSelectVO selectOrderById(Long id) {
        //1.查询订单信息
        Orders orders = orderMapper.selectById(id);
        //2.查询观演人信息
        List<ViewerInfo> viewerInfos = viewerInfoMapper.selectList(Wrappers.lambdaQuery(ViewerInfo.class)
                .eq(ViewerInfo::getOrderId, orders.getId()));
        //3.封装返回类
        List<ViewerInfoSelectVO> viewerInfoSelectVOS = viewerInfos.stream()
                .map(viewerInfo -> new ViewerInfoSelectVO()
                        .setViewerName(viewerInfo.getViewerName())
                        .setViewerPhone(viewerInfo.getViewerPhone())
                        .setViewerId(viewerInfo.getViewerId()))
                .toList();
        OrderSelectVO orderSelectVO = BeanUtil.copyProperties(orders, OrderSelectVO.class);
        orderSelectVO.setViewerInfoSelectVOS(viewerInfoSelectVOS);
        orderSelectVO.setTicketCategory(programClient.ticketCategorySelect(orders.getTicketId()).getData());

        return orderSelectVO;
    }
}
